﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Vortex.Utils {

	/// <summary>
	/// Contains hi-resolution timer methods
	/// </summary>
	public class HighResoltionTimer {
		/// <summary>
		/// Queries the performance counter.
		/// </summary>
		/// <param name="lpPerformanceCount">The performance timer ticks count.</param>
		/// <returns></returns>
		[DllImport("Kernel32.dll")]
        public static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

		/// <summary>
		/// Queries the performance timer frequency.
		/// </summary>
		/// <param name="lpFrequency">The frequency.</param>
		/// <returns></returns>
        [DllImport("Kernel32.dll")]
        public static extern bool QueryPerformanceFrequency(out long lpFrequency);


		/// <summary>
		/// Initializes static members of the <see cref="HiResTimer"/> class.
		/// </summary>
		static HighResoltionTimer() {
			long frequency;
			QueryPerformanceFrequency(out frequency);
			Frequency = (double)frequency;
			Rate = 1 / Frequency;
		}

		/// <summary>
		/// Gets the current hi resolution timer ticks.
		/// </summary>
		/// <value>The timer ticks.</value>
		static public long Ticks {
			get {
				long ticks;
				QueryPerformanceCounter(out ticks);
				return ticks;
			}
		}

		/// <summary>
		/// Gets the hi-resolution timer frequency.
		/// </summary>
		/// <value>The timer frequency.</value>
		static public double Frequency {
			get;
			private set;
		}

		/// <summary>
		/// Gets the hi-resolution timer rate (inverted frequency).
		/// </summary>
		/// <value>1 / Frequency.</value>
		static public double Rate {
			get;
			private set;
		}
	}

	/// <summary>
	/// Represents high-resolution timer snapshot
	/// </summary>
	public struct PerfTime {
		private long _ticks;

		/// <summary>
		/// Gets the ticks of timer snapshot.
		/// </summary>
		/// <value>The timer ticks.</value>
		public long Ticks {
			get { return _ticks; }
		}

		/// <summary>
		/// Gets the current timer snapshot.
		/// </summary>
		/// <value>The performance timer snapshot.</value>
		public static PerfTime Now {
			get { return new PerfTime(HighResoltionTimer.Ticks); }
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PerfTime"/> struct with tick count.
		/// </summary>
		/// <param name="ticks">The timer ticks.</param>
		public PerfTime(long ticks) {
			_ticks = ticks;
		}

		#region Operators

		public static PerfTimeSpan operator -(PerfTime left, PerfTime right) {
			return new PerfTimeSpan(left.Ticks - right.Ticks);
		}

		public static PerfTime operator -(PerfTime left, PerfTimeSpan right) {
			return new PerfTime(left.Ticks - right.Ticks);
		}

		public static PerfTime operator +(PerfTime left, PerfTimeSpan right) {
			return new PerfTime(left.Ticks + right.Ticks);
		}

		#endregion

	}

	/// <summary>
	/// Period between two performance timer snapshots
	/// </summary>
	public struct PerfTimeSpan {
		private long _ticks;

		/// <summary>
		/// Initializes a new instance of the <see cref="PerfTimeSpan"/> with perf timer ticks ellapsed.
		/// </summary>
		/// <param name="ticks">The ticks ellapsed.</param>
		public PerfTimeSpan(long ticks) {
			_ticks = ticks;
		}

		/// <summary>
		/// Gets the ticks ellapsed for this time span.
		/// </summary>
		/// <value>The timer ticks ellapsed.</value>
		public long Ticks {
			get { return _ticks; }
		}

		/// <summary>
		/// Gets the time span value in seconds.
		/// </summary>
		/// <value>The time expressed seconds.</value>
		public double Seconds {
			get { return (double)_ticks * HighResoltionTimer.Rate; }
		}

		/// <summary>
		/// Gets the time span value in milliseconds.
		/// </summary>
		/// <value>The time expressed milliseconds.</value>
		public double Milliseconds {
			get { return Seconds * 1000; }
		}

		/// <summary>
		/// Gets the time span value in microseconds.
		/// </summary>
		/// <value>The time expressed microseconds.</value>
		public double Microseconds {
			get { return Seconds * 1000000; }
		}

		/// <summary>
		/// Gets the time span value in nanoseconds.
		/// </summary>
		/// <value>The time expressed nanoseconds.</value>
		public double Nanoseconds {
			get { return Seconds * 1000000000; }
		}

		/// <summary>
		/// Gets the time span value in cpu ticks.
		/// </summary>
		/// <value>The cpu ticks.</value>
		public long CpuTicks {
			get { return (long)(Seconds * (double)Vortex.Wrapper.Core.CpuFrequency); }
		}

		#region Operators

		public static PerfTimeSpan operator +(PerfTimeSpan left, PerfTimeSpan right) {
			return new PerfTimeSpan(left.Ticks + right.Ticks);
		}

		public static PerfTimeSpan operator -(PerfTimeSpan left, PerfTimeSpan right) {
			return new PerfTimeSpan(left.Ticks - right.Ticks);
		}

		#endregion
	}
}
